#+TITLE: The Seasoned Schemer Notes
#+SUBTITLE: Chapter 14
#+AUTHOR: Zelphir Kaltstahl
#+DATE: [2023-02-26 So]
#+LANGUAGE: English
#+TAGS: Scheme, The Seasoned Schemer
#+CREATOR: Emacs
#+EXCLUDE_TAGS: noexport
#+OPTIONS: ^:{} H:10 toc:3
#+STARTUP: content indent align inlineimages hideblocks entitiesplain nologdone nologreschedule nologredeadline nologrefile

* Prerequisites
:PROPERTIES:
:CUSTOM_ID: prerequisites
:END:

src_scheme[:exports code]{atom?} checks, whether a thing is a non-compound thing, at least for simple code, that does not make use of vector and such things.

#+NAME: atom-def
#+BEGIN_SRC scheme :noweb strip-export :results none :exports code :eval never-export
(define atom?
  (λ (x)
    (and (not (pair? x))
         (not (null? x)))))
#+end_src

* Chapter 15
:PROPERTIES:
:CUSTOM_ID: chapter-15
:END:

** About
:PROPERTIES:
:CUSTOM_ID: about
:END:

Chapter 15 deals with usage of assignment (src_scheme[:exports code]{set!}). It explains when usage of src_scheme[:exports code]{set!} can be kind of safe (at least in a single threaded scenario). It arrives at some rules (commandments) for src_scheme[:exports code]{set!} usage.

** About the value of expressions
:PROPERTIES:
:CUSTOM_ID: expression-value
:END:

Usually expressions have a value. Exempt from this rule are src_scheme[:exports code]{define} and the assignment src_scheme[:exports code]{set!}, which makes them special.

** Differences between src_scheme[:exports code]{define} and src_scheme[:exports code]{set!}
:PROPERTIES:
:CUSTOM_ID: differences-define-set-bang
:END:

While src_scheme[:exports code]{define} can be used in many but not all contexts, src_scheme[:exports code]{set!} can be used in any context (but really should not).

One important difference is, that src_scheme[:exports code]{set!} can change values of bindings outside of the scope of the context it is used in. It depends on the binding it changes the value of to already exist (at least in GNU Guile it does), then changes the value forever. src_scheme[:exports code]{define} works differently. It introduces a new binding that can shadow bindings from outer scopes, but once the scope the src_scheme[:exports code]{define} is used in is left, the previously shadowed binding becomes visibile again.

** Making procedures remember things
:PROPERTIES:
:CUSTOM_ID: remembering-things
:END:

src_scheme[:exports code]{set!} can be used to make procedures remember things. For example:

#+NAME: rememberer
#+begin_src scheme :noweb strip-export :results output replace drawer :wrap example :exports both :eval never-export :language guile
(define memory 'still-empty)
(define rememberer
  (λ (. something-to-remember)
    (when (not (null? something-to-remember))
      (set! memory something-to-remember))
    (cons something-to-remember
          (cons memory '()))))
#+end_src

#+NAME: usage-rememberer
#+begin_src scheme :noweb strip-export :results output replace drawer :wrap example :exports both :eval never-export :language guile
<<rememberer>>
(simple-format #t "~a\n" (rememberer 'something-heartwarming))
(simple-format #t "memory contains: ~a\n" memory)
(newline)

(simple-format #t "~a\n" (rememberer 'another-great-recollection))
(simple-format #t "memory contains: ~a\n" memory)
(newline)

(simple-format #t "~a\n" (rememberer))
(simple-format #t "memory still contains: ~a\n" memory)
#+end_src

#+RESULTS: usage-rememberer
#+begin_example
((something-heartwarming) (something-heartwarming))
memory contains: (something-heartwarming)

((another-great-recollection) (another-great-recollection))
memory contains: (another-great-recollection)

(() (another-great-recollection))
memory still contains: (another-great-recollection)
#+end_example

*** A warning
:PROPERTIES:
:CUSTOM_ID: assignment-warning
:END:

Note however, that this kind of usage of src_scheme[:exports code]{set!} changes the fundamental character of our definitions. Instead of always returning the same result for the same input, our procedure definitions can now — depending on their memorized things — return different results even though the input is the same. As such they are no longer akin to mathematical functions, which has hugely negative implications for their usage.

For example there can be complications, when a binding is changed from more than 1 place in the code, especially when concurrency is involved. Procedures might return unexpected results, due to some other part of the code assigning a new value, changing the value a binding is associated with. This might not seem so dramatic initially, but wait until you want to run code concurrently ... Then suddenly code cannot simply run concurrently, but needs to be changed to be still correct. Either the whole algorithm implemented has to be changed, or some kind of mutex needs to be introduced, to avoid concurrent code executions messing up each others results. If possible one should avoid the need to change the code.

** Avoiding accidents of using src_scheme[:exports code]{set!}
:PROPERTIES:
:CUSTOM_ID: avoiding-accidents
:END:

*** Using src_scheme[:exports code]{let}
:PROPERTIES:
:CUSTOM_ID: avoiding-accidents-using-let
:END:

One can avoid some accidents when using src_scheme[:exports code]{set!} by introducing a new binding that src_scheme[:exports code]{set!} will see and relate to, instead of making src_scheme[:exports code]{set!} modify bindings from a scope outside of the procedure it is in. For example:

#+NAME: local-binding
#+begin_src scheme :noweb strip-export :results output replace drawer :wrap example :exports both :eval never-export :language guile
(define scoped-rememberer
  (let ([memory 'empty])
    (λ (something-to-remember)
      (set! memory something-to-remember)
      (cons something-to-remember
            (cons memory '())))))
#+end_src

This way each procedure memorizing anything has its own bindings it can src_scheme[:exports code]{set!}. For example:

#+NAME: local-binding-example
#+begin_src scheme :noweb strip-export :results output replace drawer :wrap example :exports both :eval never-export :language guile
(define scoped-rememberer-1
  (let ([memory 'empty])
    (λ (. something-to-remember)
      (unless (null? something-to-remember)
        (set! memory something-to-remember))
      (cons something-to-remember
            (cons memory '())))))

(define scoped-rememberer-2
  (let ([memory 'empty])
    (λ (. something-to-remember)
      (unless (null? something-to-remember)
        (set! memory something-to-remember))
      (cons something-to-remember
            (cons memory '())))))
#+end_src

Note, that both src_scheme[:exports code]{scoped-rememberer-1} and src_scheme[:exports code]{scoped-rememberer-2} have the same name for their src_scheme[:exports code]{memory} binding.

#+NAME: local-binding-example-usage
#+begin_src scheme :noweb strip-export :results output replace drawer :wrap example :exports both :eval never-export :language guile
<<local-binding-example>>
(scoped-rememberer-1 'unthinkably-valuable-memory)
(simple-format #t "scoped-rememberer-1's memory: ~a\n" (scoped-rememberer-1))

(scoped-rememberer-2 'trivia)
(simple-format #t "scoped-rememberer-2's memory: ~a\n" (scoped-rememberer-2))

(simple-format #t "scoped-rememberer-1's memory still intact: ~a\n" (scoped-rememberer-1))
#+end_src

#+RESULTS: local-binding-example-usage
#+begin_example
scoped-rememberer-1's memory: (() (unthinkably-valuable-memory))
scoped-rememberer-2's memory: (() (trivia))
scoped-rememberer-1's memory still intact: (() (unthinkably-valuable-memory))
#+end_example

As we can see the memory of src_scheme[:exports code]{scoped-rememberer-1} is left intact when src_scheme[:exports code]{scoped-rememberer-2} is called. The binding for the memory is local to src_scheme[:exports code]{scoped-rememberer-1} and cannot be directly accessed from outside the procedure call. It is not a global binding.

To only ever use src_scheme[:exports code]{set!} for local bindings is the idea of the [[file:~/dev/guile/the-seasoned-schemer-notes/commandments.org::#commandment-16][Sixteenth Commandment]].

*** Using src_scheme[:exports code]{let} outside of src_scheme[:exports code]{lambda}
:PROPERTIES:
:CUSTOM_ID: avoiding-accidents-using-let-outside-of-lambda
:END:

However, for making a procedure that memorizes things using a src_scheme[:exports code]{let} alone does not prevent accidents. It also needs to be outside of the src_scheme[:exports code]{lambda} that is returned for src_scheme[:exports code]{define}. For example the following definition does not make a procedure that memorizes things:

#+NAME: local-binding-no-memory
#+begin_src scheme :noweb strip-export :results output replace drawer :wrap example :exports both :eval never-export :language guile
(define non-rememberer
  (λ (. something-to-forget)
    (let ([memory 'empty])
      (unless (null? something-to-forget)
        (set! memory something-to-forget))
      (cons something-to-forget
            (cons memory
                  '())))))
#+end_src

This definition uses the same elements as before, but due to how the elements are nested, the memorization does not work:

#+NAME: local-binding-no-memory-usage
#+begin_src scheme :noweb strip-export :results output replace drawer :wrap example :exports both :eval never-export :language guile
<<local-binding-no-memory>>
(simple-format #t "non-rememberer: ~a\n" (non-rememberer 'lost-thought))
(simple-format #t "non-rememberer's memory: ~a\n" (non-rememberer))
#+end_src

#+RESULTS: local-binding-no-memory-usage
#+begin_example
non-rememberer: ((lost-thought) (lost-thought))
non-rememberer's memory: (() empty)
#+end_example

This leads to the [[file:~/dev/guile/the-seasoned-schemer-notes/commandments.org::#commandment-17][Seventeenth Commandment]].

*** Using src_scheme[:exports code]{set!} only for obsolete bindings
:PROPERTIES:
:CUSTOM_ID: avoiding-accidents-using-set-only-for-obsolete-bindings
:END:

One should only change a binding using src_scheme[:exports code]{set!}, when the binding as it is before changing it, is no longer needed. For example the following fails:

#+NAME: set-for-obsolete-bindings-wrong-swap
#+begin_src scheme :noweb strip-export :results output replace drawer :wrap example :exports both :eval never-export :language guile
(define a 1)
(define b 2)
(define wrong-swap
  (λ ()
    (set! a b)
    (set! b a)))
#+end_src

In this case src_scheme[:exports code]{a} is still needed after it is changed to refer to the same value as src_scheme[:exports code]{b}, namely when changing src_scheme[:exports code]{b} to refer to the same value as src_scheme[:exports code]{a} in the next src_scheme[:exports code]{set!}.

Compare src_scheme[:exports code]{wrong-swap} with the following src_scheme[:exports code]{correct-swap}:

#+NAME: set-for-obsolete-bindings-correct-swap
#+begin_src scheme :noweb strip-export :results output replace drawer :wrap example :exports both :eval never-export :language guile
(define a 1)
(define b 2)
(define correct-swap
  (λ ()
    (let ([tmp a])
      (set! a b)
      (set! b tmp))))
#+end_src

In src_scheme[:exports code]{correct-swap} the value src_scheme[:exports code]{a} refers to is bound to src_scheme[:exports code]{tmp}, so that there is no longer a need to use the binding src_scheme[:exports code]{a}, when assigning src_scheme[:exports code]{b}, because one can then make use of src_scheme[:exports code]{tmp} instead.
